package main

import (
	"fmt"
	"gitee.com/shu2015626/go_start_imooc/chapter05-interface/retriever/mock"
	"gitee.com/shu2015626/go_start_imooc/chapter05-interface/retriever/real"
	"time"
)

type Retriever interface {
	Get(url string) string
}

type Poster interface {
	Post(url string, form map[string]string) string
}

const url = "https://www.imooc.com"

func download(r Retriever) string {
	return r.Get(url)
}

func post(poster Poster) {
	poster.Post(url,
		map[string]string{
			"name":   "ccmouse",
			"course": "golang",
		})
}

//接口组合
type RetrieverPoster interface {
	Retriever
	Poster
}

func session(s RetrieverPoster) string {
	s.Post(url, map[string]string{
		"contents": "anoter faked imooc.com",
	})
	return s.Get(url)
}

func inspect(r Retriever) {
	fmt.Println("Inspecting: ", r)
	// r这里是接口，
	// 传入，实现接口的struct, 存有实现者的类型和数据
	// ==> 接口变量，储存了（实现者的类型、实现者的指针（或者数值））
	// 接口变量自带指针
	// 接口变量同样采用值传递，几乎不需要使用接口的指针
	// 指针接收者实现只能以指针方式使用（real.Retriever）；值接收者都可(mock.Retriever)
	fmt.Printf(" > %T, %v\n", r, r)
	fmt.Print(" > Type Switch: ")
	switch v := r.(type) {
	case *mock.Retriever:
		fmt.Println("Contents: ", v.Contents)
	case real.Retriever:
		fmt.Println("UserAgent: ", v.UserAgent)
	}

	fmt.Println()
}

func main() {
	var r Retriever

	r = &mock.Retriever{"this is a fake imooc.com "}
	inspect(r)

	r = real.Retriever{
		UserAgent: "Mozilla/5.0",
		TimeOut:   time.Minute,
	}
	inspect(r)

	// type assertion
	//realRetriver := r.(*real.Retriever)
	//fmt.Println(realRetriver.TimeOut)
	fmt.Println("====== Type Assertion ======")
	if mockRetriver, ok := r.(*mock.Retriever); ok {
		fmt.Println(mockRetriver.Contents)
	} else {
		fmt.Println("not a mock retriever")
	}

	//fmt.Println(download(r))

	fmt.Println()
	fmt.Println("====== Try a session ======")
	s := &mock.Retriever{"this is a fake imooc.com "}
	fmt.Println(session(s))

	fmt.Println()
	fmt.Print(" > Stinger Interface: ")
	fmt.Println(s.String())
}
